#include "Mercator.h"
#include <cmath>
#include <QtMath>

using namespace ns_yht;

#define GR 6378137.0
#define GL2 20037508.342787

double Mercator::PI = 3.14159265358979323846264338327950288419716939937510;
double Mercator::mercatorMinX = -20037508.342787;
double Mercator::mercatorMinY = -20037508.342787;
double Mercator::mercatorMaxX = 20037508.342787;
double Mercator::mercatorMaxY = 20037508.342787;

Mercator::Mercator()
{
}

Mercator::~Mercator()
{
}

double Mercator::ToX(double lon)
{
	return lon * mercatorMaxX / 180.0;
}
double Mercator::ToY(double lat)
{
	double y = log(tan((90.0 + lat) * PI / 360.0)) / (PI / 180.0);
	y = y * mercatorMaxY / 180.0;
	return y;
}

double Mercator::ToLon(double x)
{
	return x / mercatorMaxX * 180.0;
}
double Mercator::ToLat(double y)
{
	double lat = y / mercatorMaxY * 180.0;
	lat = 180.0 / PI * (2.0 * atan(exp(lat * PI / 180.0)) - PI / 2.0);
	return lat;
}

double Mercator::calculateBearing(double lat1, double lon1, double lat2, double lon2)
{
	double x1 = ToX(lon1);
	double y1 = ToY(lat1);
	double x2 = ToX(lon2);
	double y2 = ToY(lat2);
	return calculateBearingXY(x1, y1, x2, y2);
}

double Mercator::calculateBearingXY(double x1, double y1, double x2, double y2)
{
	double dx = x2 - x1;
	double dy = y2 - y1;

	double bearing_rad = atan2(dx, dy);
	double bearing_deg = qRadiansToDegrees(bearing_rad);
	if (bearing_deg < 0)
	{
		bearing_deg += 360.0;
	}

	return bearing_deg;
}

double Mercator::calculateDistance(double lat1, double lon1, double lat2, double lon2)
{
	double x1 = ToX(lon1);
	double y1 = ToY(lat1);
	double x2 = ToX(lon2);
	double y2 = ToY(lat2);
	return calculateDistanceXY(x1, y1, x2, y2);
}

double Mercator::calculateDistanceXY(double x1, double y1, double x2, double y2)
{
	double dx = x2 - x1;
	double dy = y2 - y1;

	return sqrt(dx * dx + dy * dy);
}

void Mercator::calculateDistanceAndBearing(double lat1, double lon1, double lat2, double lon2, double &distance, double &bearing)
{
	double x1 = ToX(lon1);
	double y1 = ToY(lat1);
	double x2 = ToX(lon2);
	double y2 = ToY(lat2);
	calculateDistanceAndBearingXY(x1, y1, x2, y2, distance, bearing);
}

void Mercator::calculateDistanceAndBearingXY(double x1, double y1, double x2, double y2, double &distance, double &bearing)
{
	double dx = x2 - x1;
	double dy = y2 - y1;

	distance = sqrt(dx * dx + dy * dy);
	double bearing_rad = atan2(dx, dy);
	bearing = qRadiansToDegrees(bearing_rad);
	if (bearing < 0)
	{
		bearing += 360.0;
	}
}

double Mercator::centerLon(double lon1, double lon2)
{
	double x1 = ToX(lon1);
	double x2 = ToX(lon2);
	double cx = (x1 + x2) / 2;
	return ToLon(cx);
}

double Mercator::centerLat(double lat1, double lat2)
{
	double y1 = ToY(lat1);
	double y2 = ToY(lat2);
	double cy = (y1 + y2) / 2;
	return ToLat(cy);
}